// ============================================================================
//
// Copyright (C) 2006-2007 Dengues
//
// Google Group: http://groups.google.com/group/dengues
// QQ Group: 24885404
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// ============================================================================
package org.dengues.designer.ui.database.parts;

import java.util.HashMap;
import java.util.List;

import org.dengues.core.components.ENodeParameterName;
import org.dengues.core.components.NodePropertyParameter;
import org.dengues.core.property.EParameterFieldCategory;
import org.dengues.core.property.EPropertyCategory;
import org.dengues.core.sql.SqlUtils;
import org.dengues.designer.ui.database.figures.DBColumnCustomFigure;
import org.dengues.designer.ui.database.figures.DBTableCustomFigure;
import org.dengues.designer.ui.database.policies.DBColumnEditPolicy;
import org.dengues.designer.ui.database.policies.DBColumnGraphicalEditPolicy;
import org.dengues.designer.ui.database.policies.DiagramChildDirectEditPolicy;
import org.dengues.designer.ui.editors.editmanager.DiagramChildCellEditorLocator;
import org.dengues.designer.ui.editors.editmanager.DiagramChildDirectEditManager;
import org.dengues.model.DenguesModelManager;
import org.dengues.model.database.DBColumn;
import org.dengues.model.database.DatabasePackage;
import org.dengues.model.database.EMFDataType;
import org.eclipse.draw2d.ChopboxAnchor;
import org.eclipse.draw2d.ConnectionAnchor;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.gef.ConnectionEditPart;
import org.eclipse.gef.DragTracker;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.NodeEditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.RequestConstants;
import org.eclipse.gef.requests.CreationFactory;
import org.eclipse.gef.tools.ConnectionDragCreationTool;
import org.eclipse.jface.viewers.TextCellEditor;

/**
 * Qiang.Zhang.Adolf@gmail.com class global comment. Detailled comment <br/>
 * 
 * $Id: Dengues.epf 2007-12-12 qiang.zhang $
 * 
 */
public class DBColumnEditPart extends AbstractDBGraphicalEditPart implements NodeEditPart {

    /*
     * (non-Javadoc)
     * 
     * @see org.dengues.designer.ui.database.parts.AbstractDBGraphicalEditPart#getCastModel()
     */
    @Override
    public DBColumn getCastModel() {
        return (DBColumn) getModel();
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com DBColumnEditPart constructor comment.
     */
    public DBColumnEditPart() {
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "createPropertyParameters".
     * 
     * @return
     */
    @Override
    protected void createPropertyParameters() {
        NodePropertyParameter param;
        HashMap properties = getCastModel().getProperties();

        param = new NodePropertyParameter(getCastModel());
        param.setName(ENodeParameterName.DB_COLUMN_OPERATION.getName());
        param.setValue(properties.get(param.getName()) == null ? "" : properties.get(param.getName())); //$NON-NLS-1$
        param.setDisplayName(ENodeParameterName.DB_COLUMN_OPERATION.getDisplayName());
        param.setFieldCategory(EParameterFieldCategory.COMBO);
        param.setPropertyCategory(EPropertyCategory.PROPERTY);
        param.setReadOnly(false);
        param.setShow(true);
        param.setItemValues(SqlUtils.COLUMN_OPERATIONS);
        param.setItemDefault(SqlUtils.COLUMN_OPERATIONS[0]);
        param.setNbRow(1);
        propParameters.add(param);

        param = new NodePropertyParameter(getCastModel());
        param.setName(ENodeParameterName.DB_COLUMN_COMMENT.getName());
        param.setValue(properties.get(param.getName()) == null ? "" : properties.get(param.getName())); //$NON-NLS-1$
        param.setDisplayName(ENodeParameterName.DB_COLUMN_COMMENT.getDisplayName());
        param.setFieldCategory(EParameterFieldCategory.TEXT);
        param.setPropertyCategory(EPropertyCategory.PROPERTY);
        param.setReadOnly(false);
        param.setShow(true);
        param.setNbLines(4);
        param.setNbRow(2);
        propParameters.add(param);
    }

    private DBColumnCustomFigure customColumnFigure;

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#createFigure()
     */
    @Override
    protected IFigure createFigure() {
        createNodeParameters();
        customColumnFigure = new DBColumnCustomFigure(this);
        customColumnFigure.setCommandStack(((DBTableEditPart) getParent()).getCommandStack());
        return customColumnFigure;
    }

    private DiagramChildDirectEditManager directEditManager;

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.gef.editparts.AbstractEditPart#createEditPolicies()
     */
    @Override
    protected void createEditPolicies() {
        installEditPolicy(EditPolicy.GRAPHICAL_NODE_ROLE, new DBColumnGraphicalEditPolicy());
        installEditPolicy(EditPolicy.DIRECT_EDIT_ROLE, new DiagramChildDirectEditPolicy());
        installEditPolicy(EditPolicy.COMPONENT_ROLE, new DBColumnEditPolicy());

    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#getDragTracker(org.eclipse.gef.Request)
     */
    @Override
    public DragTracker getDragTracker(Request request) {
        EMFDataType emfType = getCastModel().getTable().getDbDiagram().getEmfType();
        if (EMFDataType.MAPPER.compareTo(emfType) == 0) {
            return new ConnectionDragCreationTool(new CreationFactory() {

                /*
                 * (non-Javadoc)
                 * 
                 * @see org.eclipse.gef.requests.CreationFactory#getNewObject()
                 */
                public Object getNewObject() {
                    return DenguesModelManager.getDatabaseFactory().createForeignKey();
                }

                /*
                 * (non-Javadoc)
                 * 
                 * @see org.eclipse.gef.requests.CreationFactory#getObjectType()
                 */
                public Object getObjectType() {
                    return null;
                }
            });
        } else {
            return super.getDragTracker(request);
        }

    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.emf.common.notify.Adapter#notifyChanged(org.eclipse.emf.common.notify.Notification)
     */
    public void notifyChanged(Notification notification) {
        int type = notification.getEventType();
        int id = notification.getFeatureID(DatabasePackage.class);
        switch (type) {
        case Notification.SET:
            switch (id) {
            case DatabasePackage.DB_COLUMN__X:
            case DatabasePackage.DB_COLUMN__Y:
            case DatabasePackage.DB_COLUMN__HEIGHT:
            case DatabasePackage.DB_COLUMN__WIDTH:
            case DatabasePackage.DB_COLUMN__NAME:
            case DatabasePackage.DB_COLUMN__FOREIGN_KEY:
            case DatabasePackage.DIAGRAM_CHILD__SELECTED:
            case DatabasePackage.DB_COLUMN__LINK_NAME:
                refreshVisuals();
                break;
            case DatabasePackage.DB_COLUMN__HIDDEN:
                getCastModel().getTable().setHidden(notification.getNewBooleanValue());
                break;
            }
        case Notification.ADD:
        case Notification.REMOVE:
            switch (id) {
            case DatabasePackage.DB_COLUMN__INPUTS:
                refreshTargetConnections();
                break;
            case DatabasePackage.DB_COLUMN__OUTPUTS:
                refreshSourceConnections();
                break;
            }
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.gef.editparts.AbstractEditPart#refreshVisuals()
     */
    @Override
    protected void refreshVisuals() {
        Rectangle bounds = new Rectangle(getCastModel().getX(), getCastModel().getY(), getCastModel().getWidth(), getCastModel()
                .getHeight());
        customColumnFigure.getColumnName().setText(getCastModel().getName());
        customColumnFigure.createContents();
        ((GraphicalEditPart) getParent()).setLayoutConstraint(this, getFigure(), bounds);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#getModelSourceConnections()
     */
    @Override
    protected List getModelSourceConnections() {
        return getCastModel().getOutputs();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#getModelTargetConnections()
     */
    @Override
    protected List getModelTargetConnections() {
        return getCastModel().getInputs();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.gef.NodeEditPart#getSourceConnectionAnchor(org.eclipse.gef.ConnectionEditPart)
     */
    public ConnectionAnchor getSourceConnectionAnchor(ConnectionEditPart connection) {
        return getFKAnchor();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.gef.NodeEditPart#getSourceConnectionAnchor(org.eclipse.gef.Request)
     */
    public ConnectionAnchor getSourceConnectionAnchor(Request request) {
        return getFKAnchor();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.gef.NodeEditPart#getTargetConnectionAnchor(org.eclipse.gef.ConnectionEditPart)
     */
    public ConnectionAnchor getTargetConnectionAnchor(ConnectionEditPart connection) {
        return getFKAnchor();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.gef.NodeEditPart#getTargetConnectionAnchor(org.eclipse.gef.Request)
     */
    public ConnectionAnchor getTargetConnectionAnchor(Request request) {
        return getFKAnchor();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.gef.editparts.AbstractEditPart#performRequest(org.eclipse.gef.Request)
     */
    @Override
    public void performRequest(Request req) {
        if (req.getType() == RequestConstants.REQ_DIRECT_EDIT) {
            if (directEditManager == null) {
                DBColumnCustomFigure noteFigure = (DBColumnCustomFigure) getFigure();
                directEditManager = new DiagramChildDirectEditManager(this, TextCellEditor.class,
                        new DiagramChildCellEditorLocator(noteFigure));
            }
            directEditManager.show();
        } else if (REQ_OPEN.equals(req.getType())) {

        }
        super.performRequest(req);
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getFKAnchor".
     * 
     * @return
     */
    private ConnectionAnchor getFKAnchor() {
        return new ChopboxAnchor(getFigure()) {

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.draw2d.ChopboxAnchor#getLocation(org.eclipse.draw2d.geometry.Point)
             */
            @Override
            public Point getLocation(Point reference) {
                Point point;
                point = super.getLocation(reference);
                Rectangle r = new Rectangle();
                r.setBounds(getBox());
                r.translate(-1, -1);
                r.resize(1, 1);
                getOwner().translateToAbsolute(r);

                DBTableEditPart tablePart = (DBTableEditPart) getParent();
                DBTableCustomFigure figure = tablePart.getCustomTableFigure();
                Rectangle r2 = new Rectangle();
                r2.setBounds(figure.getBounds());
                // r2.translate(-1, -1);
                // r2.resize(1, 1);
                // figure.translateToAbsolute(r2);

                int cX2 = (reference.x > (r2.x + r2.width)) ? (r2.x + r2.width) : (r2.x);

                float centerY = r.y + 0.5f * r.height;
                int cX = (reference.x > (r.x + r.width)) ? (r.x + r.width) : (r.x);
                int cY = Math.round(centerY);

                cY = (cY > r2.y + r2.height) ? (r2.y + r2.height) : cY;
                cY = (cY < r2.y) ? r2.y : cY;
                point = new Point(cX2 > cX ? cX2 : cX, cY);
                return point;
            }
        };
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.dengues.designer.ui.database.parts.AbstractDBGraphicalEditPart#createMainParameters()
     */
    @Override
    protected void createMainParameters() {
        NodePropertyParameter param;
        param = new NodePropertyParameter(getCastModel());
        param.setName(ENodeParameterName.DB_COLUMN_NAME.getName());
        param.setValue(getCastModel().getName());
        param.setDisplayName(ENodeParameterName.DB_COLUMN_NAME.getDisplayName());
        param.setFieldCategory(EParameterFieldCategory.TEXT);
        param.setPropertyCategory(EPropertyCategory.MAIN);
        param.setReadOnly(true);
        param.setShow(true);
        param.setNbRow(1);
        propParameters.add(param);

        param = new NodePropertyParameter(getCastModel());
        param.setName(ENodeParameterName.DB_COLUMN_TYPE.getName());
        param.setValue(getCastModel().getType());
        param.setDisplayName(ENodeParameterName.DB_COLUMN_TYPE.getDisplayName());
        param.setFieldCategory(EParameterFieldCategory.TEXT);
        param.setPropertyCategory(EPropertyCategory.MAIN);
        param.setReadOnly(true);
        param.setShow(true);
        param.setNbRow(1);
        propParameters.add(param);

        param = new NodePropertyParameter(getCastModel());
        param.setName(ENodeParameterName.DB_COLUMN_KEY.getName());
        param.setValue(new Boolean(getCastModel().isKey()).toString());
        param.setDisplayName(ENodeParameterName.DB_COLUMN_KEY.getDisplayName());
        param.setFieldCategory(EParameterFieldCategory.CHECK);
        param.setPropertyCategory(EPropertyCategory.MAIN);
        param.setReadOnly(true);
        param.setShow(true);
        param.setNbRow(2);
        propParameters.add(param);

        param = new NodePropertyParameter(getCastModel());
        param.setName(ENodeParameterName.DB_COLUMN_NULLABLE.getName());
        param.setValue(new Boolean(getCastModel().isNullable()).toString());
        param.setDisplayName(ENodeParameterName.DB_COLUMN_NULLABLE.getDisplayName());
        param.setFieldCategory(EParameterFieldCategory.CHECK);
        param.setPropertyCategory(EPropertyCategory.MAIN);
        param.setReadOnly(true);
        param.setShow(true);
        param.setNbRow(2);
        propParameters.add(param);

        param = new NodePropertyParameter(getCastModel());
        param.setName(ENodeParameterName.DB_COLUMN_ONLYREAD.getName());
        param.setValue(new Boolean(getCastModel().isOnlyRead()).toString());
        param.setDisplayName(ENodeParameterName.DB_COLUMN_ONLYREAD.getDisplayName());
        param.setFieldCategory(EParameterFieldCategory.CHECK);
        param.setPropertyCategory(EPropertyCategory.MAIN);
        param.setReadOnly(true);
        param.setShow(true);
        param.setNbRow(2);
        propParameters.add(param);

        param = new NodePropertyParameter(getCastModel());
        param.setName(ENodeParameterName.DB_COLUMN_DEFALUT.getName());
        param.setValue(getCastModel().getDefaultValue());
        param.setDisplayName(ENodeParameterName.DB_COLUMN_DEFALUT.getDisplayName());
        param.setFieldCategory(EParameterFieldCategory.TEXT);
        param.setPropertyCategory(EPropertyCategory.MAIN);
        param.setReadOnly(true);
        param.setShow(true);
        param.setNbRow(3);
        propParameters.add(param);

        param = new NodePropertyParameter(getCastModel());
        param.setName(ENodeParameterName.DB_COLUMN_PATTERN.getName());
        param.setValue(getCastModel().getPattern());
        param.setDisplayName(ENodeParameterName.DB_COLUMN_PATTERN.getDisplayName());
        param.setFieldCategory(EParameterFieldCategory.TEXT);
        param.setPropertyCategory(EPropertyCategory.MAIN);
        param.setReadOnly(true);
        param.setShow(true);
        param.setNbRow(4);
        propParameters.add(param);

        param = new NodePropertyParameter(getCastModel());
        param.setName(ENodeParameterName.DB_COLUMN_PRECISION.getName());
        param.setValue(getCastModel().getPrecision());
        param.setDisplayName(ENodeParameterName.DB_COLUMN_PRECISION.getDisplayName());
        param.setFieldCategory(EParameterFieldCategory.TEXT);
        param.setPropertyCategory(EPropertyCategory.MAIN);
        param.setReadOnly(true);
        param.setShow(true);
        param.setNbRow(5);
        propParameters.add(param);

        param = new NodePropertyParameter(getCastModel());
        param.setName(ENodeParameterName.DB_COLUMN_LENGTH.getName());
        param.setValue(getCastModel().getLength());
        param.setDisplayName(ENodeParameterName.DB_COLUMN_LENGTH.getDisplayName());
        param.setFieldCategory(EParameterFieldCategory.TEXT);
        param.setPropertyCategory(EPropertyCategory.MAIN);
        param.setReadOnly(true);
        param.setShow(true);
        param.setNbRow(6);
        propParameters.add(param);

    }
}
